#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <stdint.h>

#define MAX_EVENTS 10

void handle_timer_event(int tfd)
{
    uint64_t exp;
    ssize_t s;
    static  int count = 0;
    count++;

    // 读取定时器到期次数
    s = read(tfd, &exp, sizeof(uint64_t));
    if (s != sizeof(uint64_t)) 
    {
        perror("read");
        exit(EXIT_FAILURE);
    }

    // 获取当前时间并格式化
    time_t rawtime;
    struct tm * timeinfo;
    char buffer[80];
    time (&rawtime);
    timeinfo = localtime(&rawtime);
    strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",timeinfo);

    printf("Timer expired at %d %s\n",count, buffer);

}

int main() 
{
    int tfd, efd;
    struct epoll_event event, events[MAX_EVENTS];

    // 创建 timerfd
    tfd = timerfd_create(CLOCK_REALTIME_ALARM, 0);
    if (tfd == -1) 
    {
        perror("timerfd_create");
        exit(EXIT_FAILURE);
    }

    // 设置定时器间隔为 2 秒
    struct itimerspec new_value;
    new_value.it_value.tv_sec = 1;
    new_value.it_value.tv_nsec = 0;
    new_value.it_interval.tv_sec = 1;
    new_value.it_interval.tv_nsec = 0;

    // 启动定时器
    if (timerfd_settime(tfd, 0, &new_value, NULL) == -1) 
    {
        perror("timerfd_settime");
        exit(EXIT_FAILURE);
    }

    // 创建 epoll 实例
    efd = epoll_create1(0);
    if (efd == -1) 
    {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }

    // 将 timerfd 添加到 epoll 实例中
    event.data.fd = tfd;
    event.events = EPOLLIN; // 关注可读事件
    if (epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &event) == -1) 
    {
        perror("epoll_ctl");
        exit(EXIT_FAILURE);
    }

    while (1) 
    {
        int n, i;

        // 等待事件的到来
        n = epoll_wait(efd, events, MAX_EVENTS, -1);
        if (n == -1) 
        {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }

        // 处理所有就绪的事件
        for (i = 0; i < n; i++) 
        {
            if (events[i].data.fd == tfd) 
            {
                handle_timer_event(tfd); // 处理定时器事件
            }
        }
    }

    return 0;
}
